package com.cw.jeeyt.service.impl.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cw.jeeyt.common.CommonUtil;
import com.cw.jeeyt.common.Constants;
import com.cw.jeeyt.common.enums.EnumBtnIconType;
import com.cw.jeeyt.common.enums.EnumOperateFlag;
import com.cw.jeeyt.common.enums.EnumPermissionAssignType;
import com.cw.jeeyt.common.enums.EnumYn;
import com.cw.jeeyt.common.pojo.TreeNode;
import com.cw.jeeyt.common.utils.StringUtils;
import com.cw.jeeyt.service.bo.security.SecurityResourceBo;
import com.cw.jeeyt.service.bo.security.SecurityUserBo;
import com.cw.jeeyt.core.util.SessionUtil;
import com.cw.jeeyt.dao.domain.security.SecurityRoleModel;
import com.cw.jeeyt.dao.intf.security.SecurityResourceDao;
import com.cw.jeeyt.dao.intf.security.SecurityRoleDao;
import com.cw.jeeyt.dao.intf.security.SecurityRoleResourceDao;
import com.cw.jeeyt.dao.intf.security.SecurityUserDao;
import com.cw.jeeyt.dao.model.security.SecurityResourceDo;
import com.cw.jeeyt.dao.model.security.SecurityUserDo;
import com.cw.jeeyt.service.cache.InitCacheInfo;
import com.cw.jeeyt.service.converter.security.SecurityResourceConverter;
import com.cw.jeeyt.service.impl.cache.OperationCache;
import com.cw.jeeyt.service.intf.security.SecurityResourceService;
import com.cw.lang.common.utils.StringUtil;
import com.cw.lang.mybatis.dto.PageInfo;

/**
 * 资源信息业务实现类
 *
 * @author chenw
 * @version 1.0.0
 */
@Service
public class SecurityResourceServiceImpl implements SecurityResourceService {

    private static final Logger logger = LoggerFactory.getLogger(SecurityResourceServiceImpl.class);
    public static List<SecurityResourceDo> list = null;
    @Autowired
    private SecurityResourceDao securityResourceDao;
    @Autowired
    private SecurityRoleDao securityRoleDao;
    @Autowired
    private SecurityUserDao securityUserDao;
    @Autowired
    private OperationCache operationCache;
    @Autowired
    private SecurityRoleResourceDao roleResourceDao;
    private RequestMatcher urlMatcher;
    @Autowired
    private InitCacheInfo cacheInfo;
    private Map<String, Collection<ConfigAttribute>> resourceMap = null;
    @Resource
    private RedisTemplate redisTemplate;

    private List<TreeNode> treeNodeList = null;

    /** 自定义方法，当这个类放入spring容器里面，指定为初始化方法。从数据库中读取资源 */
    public Map<String, Collection<ConfigAttribute>> init() throws Exception {
        return resourceMap;
    }

    @Override
    public void refreshSecurityResource() throws Exception {
        cacheInfo.putRoleOperations();
        cacheInfo.putUserOperations();
    }

    /** 自定义方法，讲list<Role>转换为 框架需要的Collection<ConfigAttribute>数据 */
    public Collection<ConfigAttribute> ListToCollection(List<SecurityRoleModel> roles) {
        List<ConfigAttribute> list = new ArrayList<ConfigAttribute>();
        for (SecurityRoleModel role : roles) {
            list.add(new SecurityConfig(role.getName()));
        }
        return list;
    }

    /** 获取所有权限匹配属性 */
    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        Set<ConfigAttribute> allAttributes = new HashSet<ConfigAttribute>();
        for (Map.Entry<String, Collection<ConfigAttribute>> entry : resourceMap.entrySet()) {
            allAttributes.addAll(entry.getValue());
        }
        return allAttributes;
    }

    /** 接口中规定的方法， 这核心方法 ，用户获取正在访问的资源所对应的权限集合 */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        try {
            SecurityUserBo securityUser = SessionUtil.getSessionUser();
            if (securityUser == null) {
                return null;
            }
            FilterInvocation filterInvocation = (FilterInvocation) object;
            resourceMap = ((HashMap<String, Collection<ConfigAttribute>>) redisTemplate.opsForValue()
                .get(Constants.REDIS_RESOURCE));
            Iterator<String> iter = resourceMap.keySet()
                .iterator();
            while (iter.hasNext()) {
                String resUrl = iter.next();
                // 判定当前请求路径是否是受控制的权限(意思就是判断是不是库里面保存的路径)
                if (resUrl != null) {
                    urlMatcher = new AntPathRequestMatcher(resUrl);
                    if (urlMatcher.matches(filterInvocation.getHttpRequest())) {
                        return resourceMap.get(resUrl);
                    }
                }
            }
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        // 如果不是库里面的路径，就让它过去
        return null;
    }

    @Override
    public boolean supports(Class<?> arg0) {
        return true;
    }

    @Override
    public List<SecurityResourceBo> getResourceByUserName(String userName) throws Exception {

        if (StringUtils.isEmpty(userName)) {
            logger.error("用户名称为空");
            return null;
        }
        return SecurityResourceConverter.doList2BoList(securityResourceDao.getResourceByUserName(userName));
    }

    @Override
    public List<SecurityResourceBo> getResourceByRoleId(Long roleId) throws Exception {

        if (roleId == null) {
            logger.error("角色id为空");
            return null;
        }
        return SecurityResourceConverter.doList2BoList(securityResourceDao.getResourceByRoleId(roleId));
    }

    /**
     * 分页查询资源信息
     *
     * @param resourceBo
     * @param startNum
     * @param pageSize
     * @return
     * @throws Exception
     */
    @Override
    public PageInfo<SecurityResourceBo> queryByPage(SecurityResourceBo resourceBo, Integer startNum, Integer pageSize)
    throws Exception {
        PageInfo<SecurityResourceDo> pageInfo = securityResourceDao.queryByPage(
            SecurityResourceConverter.bo2Do(resourceBo), startNum, pageSize);
        return new PageInfo<>(pageInfo, SecurityResourceConverter.doList2BoList(pageInfo.getList()));
    }

    /**
     * 根据主键查寻资源信息
     *
     * @param id
     * @return
     */
    @Override
    public SecurityResourceBo getResourceById(Long id) throws Exception {
        SecurityResourceBo resourceBo = SecurityResourceConverter.do2Bo(securityResourceDao.getById(id));
        Long parentId = resourceBo.getParentId();
        if(parentId != null){
            SecurityResourceDo securityResourceDo = securityResourceDao.getById(parentId);
            if(securityResourceDo != null){
                resourceBo.setParentName(securityResourceDo.getResName());
            }
        }
        List<SecurityResourceBo> btnList = this.queryBtnListByParentId(resourceBo.getId());
        StringBuffer sb = new StringBuffer("");
        if (btnList != null && !btnList.isEmpty()) {
            int i = 0;
            for (SecurityResourceBo btn : btnList) {
                String btnCode = btn.getResTitle();
                String btnUrl = btn.getResUrl();
                if (i == 0) {
                    sb.append(btnCode + "##" + btnUrl);
                } else {
                    sb.append("," + btnCode + "##" + btnUrl);
                }
                i++;
            }
        }
        resourceBo.setBtnAuthInfo(sb.toString());
        return resourceBo;
    }

    /**
     * 保存资源菜单表
     *
     * @param securityResourceBo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer saveSecurityResource(SecurityResourceBo securityResourceBo) throws Exception {
        this.insert(securityResourceBo);
        SecurityResourceBo insertResource = getResByResNameAndParentId(securityResourceBo.getResName(),
            securityResourceBo.getParentId());
        //查询
        securityResourceBo.setId(insertResource.getId());
        //根据当前添加的按钮权限来添加按钮菜单
        String btns = securityResourceBo.getBtnList();
        if (!StringUtils.isEmpty(btns)) {
            insertBtnSecurityResource(btns, securityResourceBo);
        }
        //刷新角色权限缓存
        refreshSecurityResource();
        return 0;
    }

    /**
     * 根据父id及资源名称查询资源信息
     *
     * @param resName
     * @param parentId
     * @return
     */
    @Override
    public SecurityResourceBo getResByResNameAndParentId(String resName, Long parentId) {
        return SecurityResourceConverter.do2Bo(securityResourceDao.getResByResNameAndParentId(resName, parentId));
    }

    /**
     * 新增按钮资源
     *
     * @param btns
     * @param securityResourceBo
     * @throws Exception
     */
    private void insertBtnSecurityResource(String btns, SecurityResourceBo securityResourceBo) throws Exception {
        String[] btnInfoList = securityResourceBo.getBtnAuthInfo()
            .split(",");
        List<SecurityResourceBo> securityResourceList = new ArrayList<>();
        for (String btn : btnInfoList) {
            String[] btnInfo = btn.split("##");
            SecurityResourceBo btnMenu = new SecurityResourceBo();
            btnMenu.setParentId(securityResourceBo.getId());
            btnMenu.setParentName(securityResourceBo.getResName());
            btnMenu.setIsMenu(EnumYn.N.getCode());
            btnMenu.setIsView(EnumYn.Y.getCode());
            btnMenu.setResUrl(btnInfo[1]);
            if (EnumOperateFlag.ADD.getCode()
                .equals(btnInfo[0])) {
                btnMenu.setComment(EnumOperateFlag.ADD.getDescription());
                btnMenu.setResIcon(EnumBtnIconType.ICON_ADD.getCode());
                btnMenu.setResName(EnumOperateFlag.ADD.getDescription());
                btnMenu.setResTitle(EnumOperateFlag.ADD.getCode());
                btnMenu.setResOrder(1);
            } else if (EnumOperateFlag.EDIT.getCode()
                .equals(btnInfo[0])) {
                btnMenu.setComment(EnumOperateFlag.EDIT.getDescription());
                btnMenu.setResIcon(EnumBtnIconType.ICON_EDIT.getCode());
                btnMenu.setResName(EnumOperateFlag.EDIT.getDescription());
                btnMenu.setResTitle(EnumOperateFlag.EDIT.getCode());
                btnMenu.setResOrder(2);
            } else if (EnumOperateFlag.DELETE.getCode()
                .equals(btnInfo[0])) {
                btnMenu.setComment(EnumOperateFlag.DELETE.getDescription());
                btnMenu.setResIcon(EnumBtnIconType.ICON_DELETE.getCode());
                btnMenu.setResName(EnumOperateFlag.DELETE.getDescription());
                btnMenu.setResTitle(EnumOperateFlag.DELETE.getCode());
                btnMenu.setResOrder(3);
            } else if (EnumOperateFlag.VIEW.getCode()
                .equals(btnInfo[0])) {
                btnMenu.setComment(EnumOperateFlag.VIEW.getDescription());
                btnMenu.setResIcon(EnumBtnIconType.ICON_VIEW.getCode());
                btnMenu.setResName(EnumOperateFlag.VIEW.getDescription());
                btnMenu.setResTitle(EnumOperateFlag.VIEW.getCode());
                btnMenu.setResOrder(4);
            } else if (EnumOperateFlag.SAVE.getCode()
                .equals(btnInfo[0])) {
                btnMenu.setComment(EnumOperateFlag.SAVE.getDescription());
                btnMenu.setResIcon(EnumBtnIconType.ICON_SAVE.getCode());
                btnMenu.setResName(EnumOperateFlag.SAVE.getDescription());
                btnMenu.setResTitle(EnumOperateFlag.SAVE.getCode());
                btnMenu.setResOrder(5);
            } else if (EnumOperateFlag.SUBMIT.getCode()
                .equals(btnInfo[0])) {
                btnMenu.setComment(EnumOperateFlag.SUBMIT.getDescription());
                btnMenu.setResIcon(EnumBtnIconType.ICON_SUBMIT.getCode());
                btnMenu.setResName(EnumOperateFlag.SUBMIT.getDescription());
                btnMenu.setResTitle(EnumOperateFlag.SUBMIT.getCode());
                btnMenu.setResOrder(6);
            }
            securityResourceList.add(btnMenu);
        }
        if (securityResourceList != null && !securityResourceList.isEmpty()) {
            insertBat(securityResourceList);
        }
    }

    @Override
    public void insertBat(List<SecurityResourceBo> securityResourceList) throws Exception {
        if (securityResourceList == null || securityResourceList.isEmpty()) {
            logger.error("批量新增的资源信息为空");
            return;
        }
        List<SecurityResourceDo> srList = new ArrayList<SecurityResourceDo>();
        SecurityUserBo securityUser = SessionUtil.getSessionUser();
        for (SecurityResourceBo securityResource : securityResourceList) {
            SecurityResourceDo resource = SecurityResourceConverter.bo2Do(securityResource);
            resource.setCreateBy(securityUser.getId());
            resource.setCreateDate(new Date());
            resource.setUpdateBy(securityUser.getId());
            resource.setUpdateDate(new Date());
            srList.add(resource);
        }
        securityResourceDao.insertBat(srList);
    }

    /**
     * 判断访问URL是否需要访问权限
     *
     * @param url
     * @return
     */
    @Override
    public boolean checkResourceNeedAuth(String url) {
        return securityResourceDao.checkResourceNeedAuth(url) > 0;
    }

    /**
     * 新增资源信息
     *
     * @param resourceBo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean insert(SecurityResourceBo resourceBo) throws Exception {

        if (resourceBo == null) {
            logger.error("资源信息为空");
            return false;
        }
        SecurityUserBo securityUser = SessionUtil.getSessionUser();
        SecurityResourceDo resource = SecurityResourceConverter.bo2Do(resourceBo);
        resource.setCreateBy(securityUser.getId());
        resource.setCreateDate(new Date());
        resource.setUpdateBy(securityUser.getId());
        resource.setUpdateDate(new Date());
        return securityResourceDao.insert(resource) > 0;
    }

    /**
     * 更新资源信息
     *
     * @param resourceBo
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void update(SecurityResourceBo resourceBo) throws Exception {

        if (resourceBo == null) {
            logger.error("资源信息为空");
            return;
        }
        SecurityUserBo securityUser = SessionUtil.getSessionUser();
        SecurityResourceDo resource = SecurityResourceConverter.bo2Do(resourceBo);
        resource.setUpdateBy(securityUser.getId());
        resource.setUpdateDate(new Date());
        securityResourceDao.update(resource);
        //刷新角色权限缓存
        refreshSecurityResource();
    }

    /**
     * 删除资源信息
     *
     * @param resourceBo
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(SecurityResourceBo resourceBo) throws Exception {

        if (resourceBo == null) {
            logger.error("资源信息为空");
            return;
        }
        securityResourceDao.delete(SecurityResourceConverter.bo2Do(resourceBo));
        //删除对应的角色资源
        roleResourceDao.deleteByResId(resourceBo.getId());
        //刷新角色权限缓存
        refreshSecurityResource();
    }

    /**
     * 同步菜单信息到资源信息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void asyncResource(String resourceJson) throws Exception {

        JSONArray array = JSON.parseArray(resourceJson);
        if (array != null && !array.isEmpty()) {
            for (int i = 0; i < array.size(); i++) {
                JSONObject obj = (JSONObject) array.get(i);
                SecurityResourceDo securityResource = JSONObject.parseObject(
                    JSON.toJSONString(obj, CommonUtil.getFeatures()), SecurityResourceDo.class);
                if (securityResource != null) {
                    SecurityResourceDo sr = securityResourceDao.getById(securityResource.getId());
                    //如果已经存在则更新，不存在则新增
                    if (sr != null) {
                        securityResourceDao.update(securityResource);
                    } else {
                        securityResourceDao.insert(securityResource);
                    }
                }
            }
        }
    }

    /**
     * 查询资源信息资源信息树json数据
     *
     * @param type
     * @param assignId
     * @param parentIsOpen
     * @param childIsOpen
     * @return
     * @throws Exception
     */
    @Override
    public String queryResourceJson(Long resParentId, String type, Long assignId, boolean parentIsOpen,
        boolean childIsOpen) throws Exception {

        List<SecurityResourceDo> securityRoleResourceList = null;
        List<SecurityResourceDo> securityUserResourceList = null;
        if (EnumPermissionAssignType.ROLE.getCode()
            .equals(type)) {
            securityRoleResourceList = securityResourceDao.getResourceByRoleId(assignId);
        } else if (EnumPermissionAssignType.USER.getCode()
            .equals(type)) {
            SecurityUserDo securityUser = securityUserDao.getById(assignId);
            List<SecurityRoleModel> roleList = securityRoleDao.getRolesByUserId(assignId);
            if (roleList != null && !roleList.isEmpty()) {
                String[] roles = new String[roleList.size()];
                int i = 0;
                for (SecurityRoleModel role : roleList) {
                    if (i == 0) {
                        roles[i] = role.getId()
                            .toString();
                    } else {
                        roles[i] = "," + role.getId()
                            .toString();
                    }
                    i++;
                }
                securityRoleResourceList = securityResourceDao.getResourcesByUserRoles(roles);
            }
            securityUserResourceList = securityResourceDao.getResourceByUserName(securityUser.getUsername());
        }
        SecurityResourceDo securityResource = securityResourceDao.getById(resParentId);
        if (securityResource == null) {
            throw new Exception("上级资源信息为空:" + resParentId);
        }
        //加载根部资源信息
        List<SecurityResourceDo> securityResourceList = securityResourceDao.queryResourceList();
        treeNodeList = new ArrayList<TreeNode>();
        TreeNode parentNode = new TreeNode();
        parentNode.setId(securityResource.getId());
        parentNode.setIsMenu(securityResource.getIsMenu());
        parentNode.setName(securityResource.getResName());
        parentNode.setOpen(true);
        treeNodeList.add(parentNode);
        if (securityResourceList != null && !securityResourceList.isEmpty()) {
            for (SecurityResourceDo sm : securityResourceList) {
                if (sm.getId()
                    .equals(resParentId)) {
                    continue;
                }
                TreeNode treeNode = initTreNode(sm, securityRoleResourceList, securityUserResourceList, type);
                treeNodeList.add(treeNode);
            }
        }
        return JSON.toJSONString(treeNodeList);
    }

    /**
     * 根据父id查询所有的按钮资源
     *
     * @param parentId
     * @return
     */
    private List<SecurityResourceBo> queryBtnListByParentId(Long parentId) {
        return SecurityResourceConverter.doList2BoList(securityResourceDao.queryBtnListByParentId(parentId));
    }

    private TreeNode initTreNode(SecurityResourceDo sm, List<SecurityResourceDo> securityRoleResourceList,
        List<SecurityResourceDo> securityUserResourceList, String type) {
        TreeNode treeNode = new TreeNode();
        treeNode.setId(sm.getId());
        treeNode.setIsMenu(sm.getIsMenu());
        treeNode.setName(sm.getResName());
        treeNode.setOpen(true);
        treeNode.setpId(sm.getParentId());
        Long resId = sm.getId();
        if (securityRoleResourceList != null && !securityRoleResourceList.isEmpty()) {
            boolean isExist = false;
            for (SecurityResourceDo sr : securityRoleResourceList) {
                if (resId.equals(sr.getId())) {
                    isExist = true;
                    break;
                }
            }
            if (isExist) {
                treeNode.setChecked(true);
                if (EnumPermissionAssignType.USER.getCode()
                    .equals(type)) {
                    treeNode.setChkDisabled("true");
                }
            }
        }
        if (EnumPermissionAssignType.USER.getCode()
            .equals(type)) {
            if (securityUserResourceList != null && !securityUserResourceList.isEmpty()) {
                boolean isExist = false;
                for (SecurityResourceDo sr : securityUserResourceList) {
                    if (sr.getId() == resId) {
                        isExist = true;
                        break;
                    }
                }
                if (isExist) {
                    treeNode.setChecked(true);
                }
            }
        }
        return treeNode;
    }

    /**
     * 查询资源信息根节点信息
     *
     * @return
     * @throws Exception
     */
    @Override
    public SecurityResourceBo queryRootSecurityResource() throws Exception {
        return SecurityResourceConverter.do2Bo(securityResourceDao.queryRootSecurityResource());
    }

    @Override
    public void updateResourceParentId(Long id, Long parentId) throws Exception {
        if (id == null) {
            logger.error("主键id为空");
            return;
        }
        if (parentId == null) {
            logger.error("父节点id为空");
            return;
        }
        securityResourceDao.updateResourceParentId(id, parentId);
    }

    @Override
    public void updateResourceName(Long id, String resName) throws Exception {
        if (id == null) {
            logger.error("主键id为空");
            return;
        }
        if (StringUtils.isEmpty(resName)) {
            logger.error("资源名称为空");
            return;
        }
        securityResourceDao.updateResourceName(id, resName);
    }

    @Override
    public List<SecurityResourceBo> querySecurityResourceListByParentId(Long parentId) throws Exception {
        return SecurityResourceConverter.doList2BoList(
            securityResourceDao.querySecurityResourceListByParentId(parentId));
    }

    @Override
    public String queryResourceJson(Long parentId, boolean parentIsOpen, boolean childIsOpen) throws Exception {

        SecurityResourceDo securityResource = securityResourceDao.getById(parentId);
        if (securityResource == null) {
            throw new Exception("上级资源信息为空:" + parentId);
        }
        //加载根部菜单信息
        List<SecurityResourceDo> securityResourceList = securityResourceDao.queryResourceList();
        treeNodeList = new ArrayList<>();
        TreeNode parentTreeNode = new TreeNode();
        parentTreeNode.setId(securityResource.getId());
        parentTreeNode.setName(securityResource.getResName());
        parentTreeNode.setOpen(parentIsOpen);
        parentTreeNode.setIsMenu(securityResource.getIsMenu());
        parentTreeNode.setUrl(securityResource.getResUrl());
        parentTreeNode.setComment(securityResource.getComment());
        treeNodeList.add(parentTreeNode);
        if (securityResourceList != null && !securityResourceList.isEmpty()) {
            for (SecurityResourceDo sm : securityResourceList) {
                if (sm.getId()
                    .equals(parentId)) {
                    continue;
                }
                TreeNode treeNode = new TreeNode();
                treeNode.setId(sm.getId());
                treeNode.setpId(sm.getParentId());
                treeNode.setName(sm.getResName());
                treeNode.setOpen(false);
                treeNode.setIsMenu(sm.getIsMenu());
                treeNode.setUrl(sm.getResUrl());
                treeNode.setComment(sm.getComment());
                treeNodeList.add(treeNode);
            }
        }
        return JSON.toJSONString(treeNodeList);
    }

    @Override
    public PageInfo<SecurityResourceBo> querySelectSecurityResource(SecurityResourceBo securityResourceBo,
        Integer startNum, Integer pageSize) throws Exception {
        if (securityResourceBo == null) {
            logger.error("系统菜单表为空");
            return null;
        }
        PageInfo<SecurityResourceDo> pageInfo = securityResourceDao.querySelectSecurityResource(
            SecurityResourceConverter.bo2Do(securityResourceBo), startNum, pageSize);
        return new PageInfo<>(pageInfo, SecurityResourceConverter.doList2BoList(pageInfo.getList()));
    }

    /**
     * 修改系统菜单信息
     *
     * @param securityResourceBo
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateSecurityResource(SecurityResourceBo securityResourceBo) throws Exception {
        //如果所选按钮为空，则判断当前菜单下是否有按钮，有则删除
        //如果所选按钮有改动（可能新增了按钮，或删除了按钮），则需要新增或删除按钮
        SecurityResourceDo securityResource = securityResourceDao.getById(securityResourceBo.getId());
        String preBtns = securityResource.getBtnList();
        String btns = securityResourceBo.getBtnList();
        if (StringUtils.isEmpty(btns)) {
            if (!StringUtils.isEmpty(preBtns)) {
                //删除对应的角色资源
                securityResourceDao.deleteByParentId(securityResourceBo.getId());
                securityResourceDao.updateBtnList(securityResourceBo.getId(),"");
                roleResourceDao.deleteByResId(securityResourceBo.getId());
            }
        } else {
            if (StringUtils.isEmpty(preBtns)) {
                this.insertBtnSecurityResource(btns, securityResourceBo);
            } else {
                if (!btns.equals(preBtns)) {
                    //当前按钮菜单存在，之前不存在，则新增
                    //当前按钮不存在，之前按钮存在，则删除
                    //当前按钮存在，之前按钮也存在，则不处理
                    //先循环当前按钮，再循环之前的按钮
                    String[] btnList = btns.split(",");
                    String[] preBtnList = preBtns.split(",");
                    for (String btn : btnList) {
                        if (!preBtns.contains(btn)) {
                            this.insertBtnSecurityResource(btn, securityResourceBo);
                        } else {
                            //更新按钮url
                            updateBtnUrl(securityResourceBo);
                        }
                    }
                    for (String preBtn : preBtnList) {
                        if (!btns.contains(preBtn)) {
                            SecurityResourceBo btnSecurityResource = new SecurityResourceBo();
                            btnSecurityResource.setParentId(securityResourceBo.getId());
                            delete(btnSecurityResource);
                        }
                    }
                } else {
                    //更新按钮url
                    updateBtnUrl(securityResourceBo);
                }
            }
        }
        this.update(securityResourceBo);
    }

    /**
     * 更新按钮url
     *
     * @param securityResourceBo
     */
    private void updateBtnUrl(SecurityResourceBo securityResourceBo) {
        String authInfo = securityResourceBo.getBtnAuthInfo();
        if (!StringUtils.isEmpty(authInfo)) {
            String[] authList = authInfo.split(",");
            for (String btnAuth : authList) {
                SecurityResourceDo btnRes = new SecurityResourceDo();
                String[] btnAuthInfo = btnAuth.split("##");
                btnRes.setParentId(securityResourceBo.getId());
                btnRes.setResTitle(btnAuthInfo[0]);
                btnRes.setResUrl(btnAuthInfo[1]);
                securityResourceDao.updateResUrlByResTitleAndParentId(btnRes);
            }
        }
    }

    /**
     * 查询用户菜单权限
     *
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    @Override
    public String queryResourceByLoginUser(Long userId, HttpServletRequest request) throws Exception {
        Map<String, Object> menu = operationCache.getUserOperations(userId.toString());
        List<SecurityResourceDo> mList = new ArrayList<>();
        if (menu == null || menu.isEmpty()) {
            List<SecurityResourceDo> operationList = securityResourceDao.getResourcesByUserId(userId);
            List<SecurityResourceDo> menuList = new ArrayList<>();
            if (operationList != null && !operationList.isEmpty()) {
                Map<String, Object> map = new HashMap<>();
                for (SecurityResourceDo r : operationList) {//一级菜单
                    if (Constants.ROOT_RESOURCE_NO.equals(r.getParentId()
                        .toString())) {
                        menuList.add(r);
                    }
                }
                for (SecurityResourceDo r : menuList) {
                    r.setSubList(getChild(r.getId(), operationList));
                }
                map.put("menus", menuList);
                mList = menuList;
                operationCache.putUserOperations(userId, map);
            }
        } else {
            mList = (List<SecurityResourceDo>) menu.get("menus");
        }
        return convertMenuToHtml(mList, request);
    }

    private List<SecurityResourceDo> getChild(Long resId, List<SecurityResourceDo> rootMenu) {
        List<SecurityResourceDo> childMenu = new ArrayList<>();
        for (SecurityResourceDo rr : rootMenu) {
            if (resId.equals(rr.getParentId())) {
                childMenu.add(rr);
            }
        }
        for (SecurityResourceDo r : childMenu) {
            r.setSubList(getChild(r.getId(), rootMenu));
        }
        //递归退出条件
        if (childMenu.size() == 0) {
            return null;
        }
        return childMenu;
    }

    /**
     * 将菜单信息转换成HTML输出到页面
     *
     * @param menuList
     * @return
     */
    private String convertMenuToHtml(List<SecurityResourceDo> menuList, HttpServletRequest request) {

        String basePath = request.getContextPath();
        StringBuffer sb = new StringBuffer("");
        if (menuList != null && !menuList.isEmpty()) {
            //一级菜单
            for (SecurityResourceDo resource : menuList) {
                String icon = (resource.getResIcon() == null || "".equals(resource.getResIcon())) ? "" :
                    resource.getResIcon();
                sb.append("<li>");

                List<SecurityResourceDo> firstSubList = resource.getSubList();
                if (firstSubList == null || firstSubList.isEmpty()) {
                    sb.append("<a data-url='" + resource.getResUrl() + "'");
                    sb.append("data-addtabs='" + resource.getId() + "'");
                } else {
                    sb.append("<a data-url='#' ");
                }
                sb.append(" data-title='" + resource.getResName() + "' data-icon='" + icon
                    + "' class='dropdown-toggle blade-pointer'>");
                sb.append("<i class='menu-icon " + icon + "'></i>");
                sb.append("<span class='menu-text'>" + resource.getResName() + "</span>");
                if (firstSubList == null || firstSubList.isEmpty()) {
                    sb.append("<b class='arrow'></b>");
                } else {
                    sb.append("<b class='arrow fa fa-angle-down'></b>");
                }
                sb.append("</a>");
                sb.append("<b class='arrow'></b>");
                List<SecurityResourceDo> subList = resource.getSubList();
                if (subList != null && !subList.isEmpty()) {
                    sb.append("<ul class='submenu'>");
                    for (SecurityResourceDo subResource : subList) {//二级菜单
                        String subIcon = (subResource.getResIcon() == null || "".equals(subResource.getResIcon())) ?
                            "" : subResource.getResIcon();
                        sb.append("<li>");
                        String subResUrl = subResource.getResUrl();
                        if (!StringUtil.isEmpty(subResUrl)) {
                            if ("#".equals(subResUrl)) {
                                sb.append("<a data-url='" + subResUrl + "' ");
                            } else {
                                sb.append("<a data-url='" + basePath + subResUrl + "' ");
                            }
                        }
                        List<SecurityResourceDo> secondSubList = subResource.getSubList();
                        if (secondSubList == null || secondSubList.isEmpty()) {
                            sb.append("data-addtabs='" + subResource.getId() + "'");
                        }
                        sb.append(" data-title='" + subResource.getResName() + "' data-icon='" + subIcon
                            + "' class='dropdown-toggle blade-pointer'>");
                        sb.append("<i class='menu-icon " + subIcon + "'></i>" + subResource.getResName());
                        sb.append("<b class='arrow'></b>");
                        sb.append("</a>");
                        sb.append("<b class='arrow'></b>");
                        if (secondSubList != null && !secondSubList.isEmpty()) {
                            sb.append("<ul class='submenu'>");
                            for (SecurityResourceDo secondSubResource : secondSubList) {//三级菜单
                                String secondSubIcon = (secondSubResource.getResIcon() == null || "".equals(
                                    secondSubResource.getResIcon())) ? "" : secondSubResource.getResIcon();
                                sb.append("<li>");
                                String secondSubResUrl = secondSubResource.getResUrl();
                                if (!StringUtil.isEmpty(secondSubResUrl)) {
                                    if ("#".equals(secondSubResUrl)) {
                                        sb.append("<a data-url='" + secondSubResUrl + "' ");
                                    } else {
                                        sb.append("<a data-url='" + basePath + secondSubResUrl + "' ");
                                    }
                                } else {
                                    sb.append("<a data-url='' ");
                                }
                                sb.append("data-addtabs='" + secondSubResource.getId() + "' data-title='"
                                    + secondSubResource.getResName() + "' data-icon='" + secondSubIcon
                                    + "' class='dropdown-toggle blade-pointer'>");
                                sb.append(
                                    "<i class='menu-icon " + secondSubIcon + "'></i>" + secondSubResource.getResName());
                                sb.append("<b class='arrow'></b>");
                                sb.append("</a>");
                                sb.append("<b class='arrow'></b>");
                                sb.append("</li>");
                            }
                            sb.append("</ul>");
                        }
                        sb.append("</li>");
                    }
                    sb.append("</ul>");
                }
                sb.append("</li>");
            }
        }
        return sb.toString();
    }

    @Override
    public void refreshResource() throws Exception {
        cacheInfo.putAllCacheInfo();
    }
}
